import glo
import time
'''
算法核心函数
函数只要写了，就不分定义的前后顺序，都能互相调用，这点和c不同，c需要声明才不分前后顺序
'''
m1 = glo.Memory()
opt = glo.OPT()
fifo = glo.FIFO()

def block_find_by_Time():
    minTime = glo.Time[0]
    block_id = 0
    for i in range(glo.bn):
        if glo.Time[i] < minTime:
            minTime = glo.Time[i]
            block_id = i
    return block_id

'''
f = False//默认关闭计数器
'''

def block_update(content, block_id, f = False):
    data = m1.getblock(block_id)
    m1.updateblock(block_id,content)
    dataNew = m1.getblock(block_id)
    if f == True:
        glo.Time_count = glo.Time_count+1
        glo.Time[glo.Time_pos] =glo.Time_count
        glo.Time_pos = glo.Time_pos+1
        glo.Time_pos =glo.Time_pos % glo.bn
    logWrite("置换完成，内存块号：{}, 数据变化：{}--->{}" .format(block_id,data,dataNew))
    # print("置换完成，内存号：原数据：{}  ,新数据：{}" .format(block_id,data))


'''
未来最近一次使用
for() //内存块内容和后面的数据匹配
'''
def block_use(block_content,p):
    for i in range(p+1,glo.dataNum):
        if glo.a[i] == block_content:
            return i
    return glo.dataNum

'''
void block_substitution_FIFO(int p)//FIFO页面置换,p号数据
'''
def block_substitution_FIFO(p):
    block_id = block_find_by_Time()#//找到替换的内存块，更新
    block_update(glo.a[p],block_id,True)

'''
void block_substitution_OPT(int p)//opt页面置换,p号数据
'''
def block_substitution_OPT(p):
    LastPosition = -1
    block_id = -1
    for i in range(m1.pos): #//遍历内存块
        position = block_use(m1.getblock(i),p)
        if position > LastPosition:
            LastPosition = position
            block_id = i
    #//找到替换的内存块，更新
    block_update(glo.a[p],block_id)
'''
'''
def block_find(x):
    for i in range(glo.bn):
        if m1.getblock(i) == x :
            return i
    return -1
'''
内存初始化
'''
def init_block():
    m1.init_M()#//基本初始化
    glo.Time_count = 0
    print("内存块总数：",end='')
    # glo.bn = int(input())
    glo.bn = int(glo.put0_string)
    logWrite("内存块总数：{}".format(glo.bn))
    for i in range(glo.bn): # -1填充几个可以直接使用的内存块
        m1.block.append(-1)
    for i in range(glo.bn):#-1填充每个计数器
        glo.Time.append(-1)
    print('内存原存有数据 总数：')
    # n = int(input())#//原有数据,必定都可以存入，n <= MAX
    n = int(glo.put1_string)
    logWrite('内存原存有数据 总数：{}'.format(n))
    if n:#为原数据 在进入算法前决定是否计数，
        print("开启计数器？")
        print('1：开启')
        print("回车：关闭")
        print('============================')
        # //f:计数器开启标志,空回车为False
        # f = bool(input())
        f = bool(glo.put3_string)
        print("原数据分别为(多行输入)：")
        #b = []
        # while n:
        #     # x 数据
        #     x = int(input())
        #     b.append(x)
        #     block_insert(x,f)
        #     n = n -1
        b = stringToIntList(glo.put2_string)
        for item in b:
            block_insert(item, f)
        logWrite("原数据分别为(多行输入)：{}".format(b))


'''
插入内容
'''
def block_insert(x,f = False):#//初始时存入,默认关闭计数器
    m1.block[m1.pos] = x
    m1.pos = m1.pos+1
    if f == True:
        glo.Time_count = glo.Time_count +1
        glo.Time[glo.Time_pos] =glo.Time_count
        glo.Time_pos = glo.Time_pos+1
        glo.Time_pos = glo.Time_pos % glo.bn

'''
OPT算法，默认开启日志log.txt
'''
def OPT():
    print('==================正在进行 OPT 最佳置换算法测试=======================')
    logWrite('==================正在进行 OPT 最佳置换算法测试=======================')
    print("测试数据总数：")
    # n = int(input())
    n = int(glo.put4_string)
    glo.dataNum = n
    logWrite('测试数据总数：{}'.format(n))
    print("分别为(逐行输入)：")
    # for i in range(n):
    #     x = int(input())
    #     glo.a.append(x)
    data = stringToIntList(glo.put5_string)
    for i in range(n):
        glo.a.append(data[i])
    logWrite('分别为：{}'.format(glo.a))
    for i in range(n):
        res =block_find(glo.a[i])
        if res >=0:
            logWrite("{} 已存在，内存块号为：{}".format(glo.a[i], res))
        else:
            logWrite("{} 不在内存块中，将插入或置换".format(glo.a[i]))
            m1.upRMCount()#//缺页中断一次
            f = m1.isFull()
            if f == -100:
                logWrite("内存块已满，将执行置换")
                m1.upRCount()#//置换一次
                block_substitution_OPT(i)
            else:
                logWrite("内存未满，将{} 添加到空闲块中，内存块号：{}".format(glo.a[i], f))
                block_insert(glo.a[i])

    glo.res6_string =m1.getBlocks()
    glo.res7_string = m1.getRMCount()
    glo.res8_string = m1.getRCount()
    logWrite("内存块最终序列：{}".format(glo.res6_string))
    logWrite("缺页中断：{}次 页面置换：{}次" .format(m1.getRMCount(),m1.getRCount()))
    #可视化变量赋值
    opt.PMCount = m1.getRMCount()
    opt.RCount = m1.getRCount()
    opt.Rate = opt.PMCount/glo.dataNum
    # print("缺页中断：{}次 页面置换：{}次" .format(m1.getRMCount(),m1.getRCount()))
    init_after_end()
    logWrite('=============================测试到此结束========================')

'''
FIFO算法
'''
def FIFO():
    print("==================正在进行 FIFO 最佳置换算法测试======================")
    logWrite("==================正在进行 FIFO 最佳置换算法测试======================")
    print("测试数据总数：",end='')
    # n = int(input())
    n = int(glo.put4_string)
    logWrite("测试数据总数：{}".format(n))
    glo.dataNum = n
    print("分别为（逐行输入）：")
    # for i in range(n):
    #     x = int(input())
    #     glo.a.append(x)
    data = stringToIntList(glo.put5_string)
    for i in range(n):
        glo.a.append(data[i])
    logWrite("分别为： {}".format(glo.a))
    for i in range(n):
        res =block_find(glo.a[i])
        if res >=0:
            # print("已存在，在第{} 个内存块中".format(res))
            logWrite("{} 已存在，内存块号为：{}".format(glo.a[i], res))
        else:
            logWrite("{}不在内存块中，插入或置换".format(glo.a[i]))
            # print("{}不在内存块中，插入或置换".format(glo.a[i]))
            m1.upRMCount()#//缺页中断一次
            f = m1.isFull()
            if f == -100:
                logWrite("内存块已满，将执行置换")
                # print("内存块已满，将执行置换")
                m1.upRCount()#//置换一次
                block_substitution_FIFO(i)
            else:
                logWrite("内存未满，将{} 添加到空闲块中，内存块号：{}".format(glo.a[i],f))
                # print("内存未满，将{} 添加到空闲块中，内存块号：{}".format(glo.a[i],f))
                block_insert(glo.a[i],True)

    # print("内存块最终结果：")
    glo.res6_string = m1.getBlocks()
    glo.res7_string = m1.getRMCount()
    glo.res8_string = m1.getRCount()
    logWrite("内存块最终序列：{}".format(glo.res6_string))
    logWrite("缺页中断：{}次 页面置换：{}次".format(m1.getRMCount(), m1.getRCount()))
    # 可视化变量赋值
    fifo.PMCount = m1.getRMCount()
    fifo.RCount = m1.getRCount()
    fifo.Rate = fifo.PMCount / glo.dataNum
    print(fifo.PMCount,fifo.RCount,fifo.Rate)
    # print("缺页中断：{}次 页面置换：{} 次".format(m1.getRMCount(),m1.getRCount()))
    init_after_end()
    logWrite('=============================测试到此结束========================')
'''
菜单
'''
def menu():
    print("============================")
    print("|      指令                |")
    print("| 0:  OPT算法              |")
    print("| 1:  FIFO算法             |")
    print("============================")
    print("指令:")
    # x = int(input())
    x = glo.order
    if x == 0:
        OPT()
    elif x == 1:
        FIFO()
    else:
        print("输入指令有误，请检查")


def logWrite(txt):
    with open('./log.txt', 'a') as fp:
        t = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
        fp.write('['+t+']   '+txt+'\n')


def stringToIntList(a):
    a = a.split()
    for i in range(len(a)):
        a[i] = int(a[i])
    return a

def init_after_end():
    #输入序列初始化
    glo.a = []
    glo.dataNum = 0
    #内存初始化
    glo.bn = 0
    m1.destory()
    #时钟初始化
    glo.Time = []
    glo.Time_pos = 0
    glo.Time_count = 0